package com.xu.cloud.common.filter;

import com.xu.cloud.common.constant.LogConstant;
import com.xu.cloud.common.constant.OrderConstant;
import com.xu.cloud.common.trace.TraceIdHelper;
import com.xu.cloud.common.api.ApiContext;
import com.xu.cloud.common.api.ApiContextHolder;
import com.xu.cloud.common.util.IpUtil;
import com.xu.cloud.common.util.LocalDateTimeUtil;
import com.xu.cloud.common.util.RandomUtil;
import com.xu.cloud.common.util.ServletLogUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.core.annotation.Order;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Duration;
import java.time.LocalDateTime;

/**
 * 交易参数设置过滤器
 *
 * @author xuguan
 * @since 2024/1/9
 */
@Order(value = OrderConstant.REQUEST_CONTEXT_FILTER_ORDER)
@WebFilter(description = "交易参数设置过滤器", urlPatterns = "/*")
public class ApiContextFilter extends BaseRequestFilter {
    private static final Logger log = LoggerFactory.getLogger(ApiContextFilter.class);

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        final LocalDateTime reqTime = LocalDateTimeUtil.currentDateTime();
        final String traceId = TraceIdHelper.getTraceId();
        // MDC日志上下文设置全局traceId
        MDC.put(LogConstant.TRACE_ID, traceId);
        final String reqJournalNo = generateReqJournalNo();

        // 创建HttpRequestContext
        ApiContext apiContext = ApiContextHolder.getOrSetTransContext();
        apiContext.setReqTime(reqTime);
        apiContext.setTraceId(traceId);
        apiContext.setReqJournalNo(reqJournalNo);
        apiContext.setClientIp(IpUtil.getClientIp(request));
        apiContext.setApiPath(request.getRequestURI());
        apiContext.setHttpServletRequest(request);
        apiContext.setHttpServletResponse(response);

        try {
            filterChain.doFilter(request, response);
        } finally {
            final LocalDateTime respTime = LocalDateTimeUtil.currentDateTime();
            apiContext.setRespTime(respTime);
            final long transCostMillis = Duration.between(reqTime, respTime).toMillis();
            apiContext.setTransCostMillis(transCostMillis);

            log.info("请求执行时间: {}ms", transCostMillis);

            // 请求预览日志
            ServletLogUtil.requestPreviewLog();

            // 清空日志
            MDC.clear();
            // 清除本地线程参数
            ApiContextHolder.remove();
        }
    }

    /**
     * 生成默认reqJournalNo
     */
    private String generateReqJournalNo() {
        return LocalDateTimeUtil.fmtCurrentPureDateTime() + RandomUtil.genRandomNum(6);
    }
}
